import { Position } from '@xyflow/react'
export function generateorXY(arrs) {
  return {
    x: arrs[0],
    y: arrs[1],
  }
}

/**
 * 简化用户路径，移除冗余的点
 */
function simplifyUserPath(path, threshold = 10) {
  if (path.length <= 2) return path

  const simplified = [path[0]]

  for (let i = 1; i < path.length - 1; i++) {
    const prev = generateorXY(simplified[simplified.length - 1])
    const current = generateorXY(path[i])
    const next = generateorXY(path[i + 1])

    // 计算当前点到前一点的距离
    const distToPrev = Math.sqrt(Math.pow(current.x - prev.x, 2) + Math.pow(current.y - prev.y, 2))

    // 如果距离太小，跳过这个点
    if (distToPrev < threshold) {
      continue
    }

    // 检查是否形成明显的转折
    const angle1 = Math.atan2(current.y - prev.y, current.x - prev.x)
    const angle2 = Math.atan2(next.y - current.y, next.x - current.x)
    const angleDiff = Math.abs(angle1 - angle2)

    // 如果角度变化明显，保留这个点
    if (angleDiff > Math.PI / 6) {
      // 30度以上的转折
      simplified.push([current.x, current.y])
    }
  }

  simplified.push(path[path.length - 1])
  return simplified
}
/**
 * 确保路径以指定起点开始（预览模式专用）
 */
function constrainPathToStartpoint(path, startPoint) {
  if (path.length === 0) return [startPoint]

  const constrainedPath = [startPoint]

  // 添加用户绘制的所有点
  for (const point of path) {
    // 跳过与起点过于接近的点
    const lastPoint = generateorXY(constrainedPath[constrainedPath.length - 1])
    const transPoint = generateorXY(point)
    const distance = Math.sqrt(
      Math.pow(transPoint.x - lastPoint.x, 2) + Math.pow(transPoint.y - lastPoint.y, 2)
    )

    if (distance > 10) {
      // 至少10像素的距离
      constrainedPath.push(point)
    }
  }

  return constrainedPath
}
/**
 * 将路径转换为横折格式（只包含水平和垂直线段）
 */
function convertToOrthogonalSegments(path) {
  if (path.length <= 1) return path

  const orthogonalPath = [path[0]]

  for (let i = 1; i < path.length; i++) {
    const prev = generateorXY(orthogonalPath[orthogonalPath.length - 1])
    const current = generateorXY(path[i])

    const deltaX = Math.abs(current.x - prev.x)
    const deltaY = Math.abs(current.y - prev.y)

    // 决定先走水平还是垂直
    if (deltaX > deltaY) {
      // 先水平移动，后垂直移动
      if (Math.abs(current.x - prev.x) > 5) {
        // 添加水平中间点
        orthogonalPath.push([current.x, prev.y])
      }
      if (Math.abs(current.y - prev.y) > 5) {
        // 添加目标点
        orthogonalPath.push([current.x, current.y])
      }
    } else {
      // 先垂直移动，后水平移动
      if (Math.abs(current.y - prev.y) > 5) {
        // 添加垂直中间点
        orthogonalPath.push([prev.x, current.y])
      }
      if (Math.abs(current.x - prev.x) > 5) {
        // 添加目标点
        orthogonalPath.push([current.x, current.y])
      }
    }
  }

  return orthogonalPath
}
/**
 * 优化横折路径，移除不必要的转折点
 */
function optimizeOrthogonalPath(path) {
  if (path.length <= 2) return path

  const optimized = [path[0]]

  for (let i = 1; i < path.length - 1; i++) {
    const prev = generateorXY(optimized[optimized.length - 1])
    const current = generateorXY(path[i])
    const next = generateorXY(path[i + 1])

    // 检查三点是否共线
    const isHorizontalLine = Math.abs(prev.y - current.y) < 1 && Math.abs(current.y - next.y) < 1
    const isVerticalLine = Math.abs(prev.x - current.x) < 1 && Math.abs(current.x - next.x) < 1

    // 如果不共线，保留转折点
    if (!isHorizontalLine && !isVerticalLine) {
      optimized.push([current.x, current.y])
    }
  }

  optimized.push(path[path.length - 1])
  return optimized
}

export function convertUserPathToOrthogonalPreview(userPath, sourceX, sourceY) {
  if (!userPath || userPath.length < 1) {
    return [sourceX, sourceY]
  }

  // 如果只有一个点，直接返回起点到该点的路径
  if (userPath.length === 1) {
    return [[sourceX, sourceY], userPath[0]]
  }

  // 第一步：简化用户路径，移除冗余点
  const simplifiedPath = simplifyUserPath(userPath, 15)

  // 第二步：确保路径以起点开始，但不强制连接到特定终点
  const constrainedPath = constrainPathToStartpoint(simplifiedPath, [sourceX, sourceY])

  // 第三步：将路径转换为横折格式（只保留水平和垂直线段）
  const orthogonalPath = convertToOrthogonalSegments(constrainedPath)

  // 第四步：优化路径，移除不必要的转折点
  const optimizedPath = optimizeOrthogonalPath(orthogonalPath)

  return optimizedPath
}

/**
 * 计算边的折线路径点
 * 根据不同的布局方向和节点相对位置，计算出合适的折线路径点
 * @param model - 边模型，包含边的基本信息如源节点ID、目标节点ID等
 * @param nodes - 节点数据数组，包含所有节点的布局信息
 * @returns 计算后的路径点数组，如果无法计算则返回undefined
 */
export function calcPointsList(model, nodes) {
  // 初始化路径点列表，用于存储计算出的路径点
  const pointsList = []

  // 获取源节点和目标节点的模型与布局数据
  // 通过LogicFlow实例获取源节点模型，用于获取节点尺寸等信息
  const sourceNodeModel = this.lf.getNodeModelById(model.sourceNodeId)
  // 通过LogicFlow实例获取目标节点模型，用于获取节点尺寸等信息
  const targetNodeModel = this.lf.getNodeModelById(model.targetNodeId)
  // 在布局后的节点数据中查找源节点，用于获取节点位置信息
  const newSourceNodeData = nodes.find((node) => node.id === model.sourceNodeId)
  // 在布局后的节点数据中查找目标节点，用于获取节点位置信息
  const newTargetNodeData = nodes.find((node) => node.id === model.targetNodeId)

  // 数据验证，确保源节点和目标节点的模型和布局数据都存在
  if (!sourceNodeModel || !targetNodeModel || !newSourceNodeData || !newTargetNodeData) {
    // 如果任一节点数据缺失，返回undefined让LogicFlow自行处理路径计算
    return undefined
  }

  // 获取折线偏移量，默认为50，用于控制折线转折点距离节点的距离
  // 这个值决定了连线的弯曲程度和美观度
  const offset = Number(model.offset) || 50

  // 处理从左到右(LR)布局的边路径计算
  // 只有在布局方向为LR且边类型为折线时才进行处理
  if (this.option.rankdir === 'LR' && model.modelType === 'polyline-edge') {
    // 正向连线：源节点在目标节点左侧
    // 当源节点x坐标小于目标节点x坐标时，认为是正向连接
    if (newSourceNodeData.x < newTargetNodeData.x) {
      // 从源节点右侧中心出发，计算起点坐标
      pointsList.push({
        x: newSourceNodeData.x + sourceNodeModel.width / 2,
        y: newSourceNodeData.y,
      })
      // 向右延伸一段距离，创建第一个转折点
      pointsList.push({
        x: newSourceNodeData.x + sourceNodeModel.width / 2 + offset,
        y: newSourceNodeData.y,
      })
      // 垂直移动到目标节点的高度，创建第二个转折点
      pointsList.push({
        x: newSourceNodeData.x + sourceNodeModel.width / 2 + offset,
        y: newTargetNodeData.y,
      })
      // 连接到目标节点左侧中心，计算终点坐标
      pointsList.push({
        x: newTargetNodeData.x - targetNodeModel.width / 2,
        y: newTargetNodeData.y,
      })

      // 对路径点进行优化处理，移除冗余的点后返回结果
      return this.pointFilter(pointsList)
    }

    // 反向连线：源节点在目标节点右侧
    // 当源节点x坐标大于目标节点x坐标时，认为是反向连接
    if (newSourceNodeData.x > newTargetNodeData.x) {
      // 根据节点相对Y轴位置选择不同路径
      // 当源节点y坐标大于等于目标节点y坐标时，源节点在目标节点的右下方
      if (newSourceNodeData.y >= newTargetNodeData.y) {
        // 源节点在目标节点的右下方，从源节点上方出发
        pointsList.push({
          x: newSourceNodeData.x,
          y: newSourceNodeData.y + sourceNodeModel.height / 2,
        })
        // 向下延伸一段距离，创建第一个转折点
        pointsList.push({
          x: newSourceNodeData.x,
          y: newSourceNodeData.y + sourceNodeModel.height / 2 + offset,
        })
        // 水平移动到目标节点位置，创建第二个转折点
        pointsList.push({
          x: newTargetNodeData.x,
          y: newSourceNodeData.y + sourceNodeModel.height / 2 + offset,
        })
        // 连接到目标节点上方中心，计算终点坐标
        pointsList.push({
          x: newTargetNodeData.x,
          y: newTargetNodeData.y + targetNodeModel.height / 2,
        })
      } else {
        // 源节点在目标节点的右上方，从源节点下方出发
        pointsList.push({
          x: newSourceNodeData.x,
          y: newSourceNodeData.y - sourceNodeModel.height / 2,
        })
        // 向上延伸一段距离，创建第一个转折点
        pointsList.push({
          x: newSourceNodeData.x,
          y: newSourceNodeData.y - sourceNodeModel.height / 2 - offset,
        })
        // 水平移动到目标节点位置，创建第二个转折点
        pointsList.push({
          x: newTargetNodeData.x,
          y: newSourceNodeData.y - sourceNodeModel.height / 2 - offset,
        })
        // 连接到目标节点下方中心，计算终点坐标
        pointsList.push({
          x: newTargetNodeData.x,
          y: newTargetNodeData.y - targetNodeModel.height / 2,
        })
      }

      // 对路径点进行优化处理，移除冗余的点后返回结果
      return this.pointFilter(pointsList)
    }
  }

  // 处理从上到下(TB)布局的边路径计算
  // 只有在布局方向为TB且边类型为折线时才进行处理
  if (this.option.rankdir === 'TB' && model.modelType === 'polyline-edge') {
    // 正向连线：源节点在目标节点上方
    // 当源节点y坐标小于目标节点y坐标时，认为是正向连接
    if (newSourceNodeData.y < newTargetNodeData.y) {
      // 从源节点底部中心出发，计算起点坐标
      pointsList.push({
        x: newSourceNodeData.x,
        y: newSourceNodeData.y + sourceNodeModel.height / 2,
      })
      // 向下延伸一段距离，创建第一个转折点
      pointsList.push({
        x: newSourceNodeData.x,
        y: newSourceNodeData.y + sourceNodeModel.height / 2 + offset,
      })
      // 水平移动到目标节点的位置，创建第二个转折点
      pointsList.push({
        x: newTargetNodeData.x,
        y: newSourceNodeData.y + sourceNodeModel.height / 2 + offset,
      })
      // 连接到目标节点顶部中心，计算终点坐标
      pointsList.push({
        x: newTargetNodeData.x,
        y: newTargetNodeData.y - targetNodeModel.height / 2,
      })

      // 对路径点进行优化处理，移除冗余的点后返回结果
      return this.pointFilter(pointsList)
    }

    // 反向连线：源节点在目标节点下方
    // 当源节点y坐标大于目标节点y坐标时，认为是反向连接
    if (newSourceNodeData.y > newTargetNodeData.y) {
      // 当源节点x坐标大于等于目标节点x坐标时，源节点在目标节点右下方
      if (newSourceNodeData.x >= newTargetNodeData.x) {
        // 源节点在目标节点右下方，从源节点右侧出发
        pointsList.push({
          x: newSourceNodeData.x + sourceNodeModel.width / 2,
          y: newSourceNodeData.y,
        })
        // 向右延伸一段距离，创建第一个转折点
        pointsList.push({
          x: newSourceNodeData.x + sourceNodeModel.width / 2 + offset,
          y: newSourceNodeData.y,
        })
        // 垂直移动到目标节点位置，创建第二个转折点
        pointsList.push({
          x: newSourceNodeData.x + sourceNodeModel.width / 2 + offset,
          y: newTargetNodeData.y,
        })
        // 连接到目标节点右侧中心，计算终点坐标
        pointsList.push({
          x: newTargetNodeData.x + targetNodeModel.width / 2,
          y: newTargetNodeData.y,
        })
      } else {
        // 源节点在目标节点左下方，从源节点左侧出发
        pointsList.push({
          x: newSourceNodeData.x - sourceNodeModel.width / 2,
          y: newSourceNodeData.y,
        })
        // 向左延伸一段距离，创建第一个转折点
        pointsList.push({
          x: newSourceNodeData.x - sourceNodeModel.width / 2 - offset,
          y: newSourceNodeData.y,
        })
        // 垂直移动到目标节点位置，创建第二个转折点
        pointsList.push({
          x: newSourceNodeData.x - sourceNodeModel.width / 2 - offset,
          y: newTargetNodeData.y,
        })
        // 连接到目标节点左侧中心，计算终点坐标
        pointsList.push({
          x: newTargetNodeData.x - targetNodeModel.width / 2,
          y: newTargetNodeData.y,
        })
      }

      // 对路径点进行优化处理，移除冗余的点后返回结果
      return this.pointFilter(pointsList)
    }
  }

  // 无法确定路径时返回undefined，让LogicFlow自行处理
  // 当不满足上述任何条件时，返回undefined，交由LogicFlow框架处理路径计算
  return undefined
}
export function stabilizeDrawingPath(
  rawPath,
  snapThreshold = 20, // 吸附阈值
  angleThreshold = 15 // 角度阈值（度）
) {
  if (rawPath.length < 2) return rawPath

  const stabilizedPath = [rawPath[0]]

  for (let i = 1; i < rawPath.length; i++) {
    const current = generateorXY(rawPath[i])
    const previous = generateorXY(stabilizedPath[stabilizedPath.length - 1])

    // 计算移动向量
    const deltaX = current.x - previous.x
    const deltaY = current.y - previous.y
    const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)

    // 如果移动距离太小，跳过这个点
    if (distance < 5) {
      continue
    }

    // 计算移动角度
    const angle = Math.atan2(deltaY, deltaX)
    const angleDegrees = (angle * 180) / Math.PI

    // 吸附到水平或垂直方向
    const stabilizedPoint = { ...current }

    // 检查是否接近水平（0°, ±180°）
    if (
      Math.abs(angleDegrees) < angleThreshold ||
      Math.abs(Math.abs(angleDegrees) - 180) < angleThreshold
    ) {
      // 吸附到水平线
      if (Math.abs(deltaY) < snapThreshold) {
        stabilizedPoint.y = previous.y
      }
    }
    // 检查是否接近垂直（±90°）
    else if (Math.abs(Math.abs(angleDegrees) - 90) < angleThreshold) {
      // 吸附到垂直线
      if (Math.abs(deltaX) < snapThreshold) {
        stabilizedPoint.x = previous.x
      }
    }
    // console.log(stabilizedPoint)

    stabilizedPoint.x && stabilizedPath.push([stabilizedPoint.x, stabilizedPoint.y])
  }

  return stabilizedPath
}
const DEFAULT_CONFIG = {
  minDistance: 20,
  offset: 30,
  cornerRadius: 0, // 直角，不使用圆角
}

/**
 * 计算路径点用于分段渲染
 * 返回优化的路径点数组，可用于创建多个独立的线段
 */
export function calculateOrthogonalPathPoints(
  sourceX,
  sourceY,
  targetX,
  targetY,
  sourcePosition,
  targetPosition,
  config = {}
) {
  const { minDistance, offset } = { ...DEFAULT_CONFIG, ...config }

  const points = []
  points.push({ x: sourceX, y: sourceY })

  // 根据源和目标位置计算路径点
  const pathPoints = getPathPoints(
    sourceX,
    sourceY,
    targetX,
    targetY,
    sourcePosition,
    targetPosition,
    minDistance,
    offset
  )

  points.push(...pathPoints)
  points.push({ x: targetX, y: targetY })

  // 优化路径点并返回
  return optimizePathPoints(points).map((i) => [i.x, i.y])
}
/**
 * 优化路径点，确保转角处的线条宽度一致
 */
function optimizePathPoints(points) {
  if (points.length < 3) return points

  const optimizedPoints = []

  for (let i = 0; i < points.length; i++) {
    const current = points[i]
    const prev = i > 0 ? points[i - 1] : null
    const next = i < points.length - 1 ? points[i + 1] : null

    // 对于转角点，稍微调整坐标确保像素对齐
    if (prev && next) {
      const isCorner =
        (Math.abs(current.x - prev.x) < 0.1 && Math.abs(current.y - next.y) < 0.1) ||
        (Math.abs(current.y - prev.y) < 0.1 && Math.abs(current.x - next.x) < 0.1)

      if (isCorner) {
        // 转角点使用整数坐标
        optimizedPoints.push({
          x: Math.round(current.x),
          y: Math.round(current.y),
        })
      } else {
        optimizedPoints.push(current)
      }
    } else {
      // 起点和终点也使用整数坐标
      optimizedPoints.push({
        x: Math.round(current.x),
        y: Math.round(current.y),
      })
    }
  }

  return optimizedPoints
}
/**
 * 根据连接方向计算路径点
 */
function getPathPoints(
  sourceX,
  sourceY,
  targetX,
  targetY,
  sourcePosition,
  targetPosition,
  minDistance,
  offset
) {
  // 水平连接（左右）
  if (isHorizontalConnection(sourcePosition, targetPosition)) {
    return getHorizontalPath(sourceX, sourceY, targetX, targetY, sourcePosition, minDistance)
  }

  // 垂直连接（上下）
  if (isVerticalConnection(sourcePosition, targetPosition)) {
    return getVerticalPath(
      sourceX,
      sourceY,
      targetX,
      targetY,
      sourcePosition,
      targetPosition,
      minDistance,
      offset
    )
  }

  // L形连接
  if (isLShapeConnection(sourcePosition, targetPosition)) {
    return getLShapePath(sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition)
  }

  // 复杂连接（需要多个转折点）
  return getComplexPath(
    sourceX,
    sourceY,
    targetX,
    targetY,
    sourcePosition,
    targetPosition,
    minDistance,
    offset
  )
}

/**
 * 判断是否为水平连接
 */
function isHorizontalConnection(sourcePosition, targetPosition) {
  return (
    (sourcePosition === Position.Right && targetPosition === Position.Left) ||
    (sourcePosition === Position.Left && targetPosition === Position.Right)
  )
}

/**
 * 判断是否为垂直连接
 */
function isVerticalConnection(sourcePosition, targetPosition) {
  return (
    (sourcePosition === Position.Bottom && targetPosition === Position.Top) ||
    (sourcePosition === Position.Top && targetPosition === Position.Bottom)
  )
}

/**
 * 判断是否为L形连接
 */
function isLShapeConnection(sourcePosition, targetPosition) {
  const horizontal = [Position.Left, Position.Right]
  const vertical = [Position.Top, Position.Bottom]

  return (
    (horizontal.includes(sourcePosition) && vertical.includes(targetPosition)) ||
    (vertical.includes(sourcePosition) && horizontal.includes(targetPosition))
  )
}

/**
 * 计算水平路径
 */
function getHorizontalPath(sourceX, sourceY, targetX, targetY, sourcePosition, minDistance) {
  const direction = sourcePosition === Position.Right ? 1 : -1
  const midX = sourceX + direction * Math.max(minDistance, Math.abs(targetX - sourceX) / 2)

  return [
    { x: midX, y: sourceY },
    { x: midX, y: targetY },
  ]
}

/**
 * 计算垂直路径
 */
function getVerticalPath(
  sourceX,
  sourceY,
  targetX,
  targetY,
  sourcePosition,
  targetPosition,
  minDistance,
  offset
) {
  const deltaX = Math.abs(targetX - sourceX)
  const deltaY = targetY - sourceY

  // 几乎垂直对齐
  if (deltaX < 10) {
    return []
  }

  // 距离较远，使用简单的Z字形
  if (Math.abs(deltaY) > 50) {
    const midY = sourceY + deltaY / 2
    return [
      { x: sourceX, y: midY },
      { x: targetX, y: midY },
    ]
  }

  // 距离较近，使用带偏移的路径避免重叠
  const direction = targetX > sourceX ? 1 : -1
  const offsetX = sourceX + offset * direction
  const sourceDirection = sourcePosition === Position.Bottom ? 1 : -1
  const targetDirection = targetPosition === Position.Top ? -1 : 1

  const midY1 = sourceY + sourceDirection * minDistance
  const midY2 = targetY + targetDirection * minDistance

  return [
    { x: sourceX, y: midY1 },
    { x: offsetX, y: midY1 },
    { x: offsetX, y: midY2 },
    { x: targetX, y: midY2 },
  ]
}

/**
 * 计算L形路径
 */
function getLShapePath(sourceX, sourceY, targetX, targetY, sourcePosition) {
  // 根据源位置决定转折点
  if (sourcePosition === Position.Right || sourcePosition === Position.Left) {
    return [{ x: targetX, y: sourceY }]
  } else {
    return [{ x: sourceX, y: targetY }]
  }
}

/**
 * 计算复杂路径（多转折点）
 */
function getComplexPath(sourceX, sourceY, targetX, targetY) {
  // 默认使用L形路径
  if (Math.abs(targetX - sourceX) > Math.abs(targetY - sourceY)) {
    return [{ x: targetX, y: sourceY }]
  } else {
    return [{ x: sourceX, y: targetY }]
  }
}
